package world.snowcrystal.openapi.service.impl.rpc;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import jakarta.annotation.Resource;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import world.snowcrystal.commons.exception.BusinessException;
import world.snowcrystal.commons.model.dto.rpc.InterfaceIdAndUserIdRequest;
import world.snowcrystal.commons.model.dto.rpc.RetrieveInterfaceInformationRequest;
import world.snowcrystal.commons.model.dto.rpc.SimpleRpcResponse;
import world.snowcrystal.commons.model.entity.InterfaceInfo;
import world.snowcrystal.commons.model.entity.UserInvokeLog;
import world.snowcrystal.commons.model.enums.ApplicationResponseStatusCode;
import world.snowcrystal.commons.model.enums.InterfaceStatusEnum;
import world.snowcrystal.commons.service.rpc.RpcInterfaceService;
import world.snowcrystal.openapi.mapper.InterfaceInfoMapper;
import world.snowcrystal.openapi.mapper.UserInvokeLogMapper;

import java.util.Optional;

@RestController
@RequestMapping({"/service/interface-info"})
public class RpcInterfaceServiceImpl implements RpcInterfaceService {


    @Resource
    private InterfaceInfoMapper mapper;

    @Resource
    private UserInvokeLogMapper userInvokeLogMapper;


    @Override
    @PostMapping({"/retrieve-interface-info"})
    public InterfaceInfo getInterfaceInfo(RetrieveInterfaceInformationRequest request) {
        String url = request.getUrl();
        String method = request.getMethod();
        if (!(StringUtils.hasText(url) && StringUtils.hasText(method))) {
            throw new BusinessException(ApplicationResponseStatusCode.PARAMS_ERROR, "path or method is null");
        }

        // region method check
        method = method.toUpperCase();
        boolean isValidMethod = false;
        for (HttpMethod httpMethod : HttpMethod.values()) {
            if (httpMethod.name().equals(method)) {
                method = httpMethod.name();
                isValidMethod = true;
                break;
            }
        }
        if (!isValidMethod) {
            throw new BusinessException(ApplicationResponseStatusCode.PARAMS_ERROR, "method is not valid");
        }
        // endregion

        if (url.endsWith("/")) {
            url = url.substring(0, url.length() - 1);
        }

        // region query
        QueryWrapper<InterfaceInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("url", url)
                .eq("method", method);
        InterfaceInfo interfaceInfo = mapper.selectOne(queryWrapper);
        if (interfaceInfo == null
                || InterfaceStatusEnum.OFFLINE.getValue().equals(interfaceInfo.getStatus())
                || InterfaceStatusEnum.DELETED.getValue().equals(interfaceInfo.getIsDelete())) {
            throw new BusinessException(ApplicationResponseStatusCode.PARAMS_ERROR, "interface not found");
        }
        // endregion

        return interfaceInfo;
    }


    @Override
    @PostMapping({"/increase-interface-invoke-count"})
    public SimpleRpcResponse<Boolean> increaseInterfaceInvokeCount(InterfaceIdAndUserIdRequest request) {
        Long interfaceId = request.getInterfaceId();
        Long userId = request.getUserId();
        // region check params
        SimpleRpcResponse.SimpleRpcResponseBuilder<Boolean> builder = SimpleRpcResponse.<Boolean>builder();
        if (interfaceId == null
                || (userId != null && userId < 0)
                || interfaceId < 0) {
            return builder.data(false).build();
        }
        // endregion

        UpdateWrapper<UserInvokeLog> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("interfaceId", interfaceId)
                .eq("userId", userId)
                .gt("remainingInvokeTimes", 0)
                .setSql("invokeCount = invokeCount + 1")
                .setSql("remainingInvokeTimes = remainingInvokeTimes - 1");
        int update = userInvokeLogMapper.update(updateWrapper);
        return builder.data(update > 0).build();
    }

    @Override
    @PostMapping({"/retrieve-remaining-invoke-count"})
    public SimpleRpcResponse<Integer> retrieveRemainingInvokeCount(InterfaceIdAndUserIdRequest request) {
        Long interfaceId = request.getInterfaceId();
        Long userId = request.getUserId();

        // region check params
        SimpleRpcResponse.SimpleRpcResponseBuilder<Integer> builder = SimpleRpcResponse.<Integer>builder();
        if (interfaceId == null
                || (userId != null && userId < 0)
                || interfaceId < 0) {
            return builder.data(0).build();
//            throw new BusinessException(ApplicationResponseStatusCode.PARAMS_ERROR, "Bad Request");
        }
        // endregion

        QueryWrapper<UserInvokeLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("interfaceId", interfaceId)
                .eq("userId", userId)
                .select("remainingInvokeTimes");
        Integer remain = Optional.of(userInvokeLogMapper.selectOne(queryWrapper).getRemainingInvokeTimes()).orElse(-1);
        return builder.data(remain).build();
    }
}
